#include "pwext.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "ex05fc.cpp"
#include <list>

// copied from ex05fd
template <typename target>
class scopegrab
{
public:
	scopegrab(weakref *ref, target *&result) : ref_(ref)
	{
		result = (target *)ref->grab();
	}
	~scopegrab()
	{
		ref_->release();
	}
protected:
	weakref *ref_;
private: 
	// prevent the default and copy constructors and
	// assignments
	scopegrab();
	scopegrab(const scopegrab &);
	void operator=(const scopegrab &);
};


// [[ex05fe]]
// DEBUG descr Usage of the scoped weak references.
class someobj
{
public:
	typedef scopegrab<someobj> somescopegrab;

	someobj() : rt_(this), other_(0)
	{ }

	~someobj()
	{
		rt_.invalidate();
		delete other_;
	}

	weakref *newweakref()
	{
		return rt_.newweakref();
	}
	void linkOther(someobj *ob)
	{
		if (other_)
			// presumably the caller must have no grabs on it
			delete other_; 
		other_ = ob->newweakref();
	}
	bool someMethod()
	{
		// just for demonstration
	// DEBUG {
		fprintf(stderr, "someMethod on %p\n", this);
	// DEBUG }
		return true;
	}
	// returns true if the call succeeded
	bool callMethodOnOther()
	{
		someobj *ob;
		somescopegrab(other_, ob);
		if (ob == 0)
	// DEBUG {
		{
			fprintf(stderr, "callMethodOnOther on %p other grab failed\n", this);
	// DEBUG }
			return false;
	// DEBUG {
		}
	// DEBUG }
		else
	// DEBUG {
		{
			fprintf(stderr, "callMethodOnOther on %p other grab succeeded\n", this);
	// DEBUG }
			return ob->someMethod();
	// DEBUG {
		}
	// DEBUG }
	}
protected:

	reftarget rt_; // this object as a target
	weakref *other_; // reference to the other object
};

// DEBUG from
void makeWorkerThread(someobj *o);

void createWorkers()
{
// DEBUG to
// ... creation ...
	someobj *a = new someobj;
	someobj *b = new someobj;
	a->linkOther(b);
	b->linkOther(a);
	makeWorkerThread(a);
	makeWorkerThread(b);
// DEBUG from
}

pw::semaphore started(0);
pw::event mayrun;

class worker : public pw::pwthread
{
public:
	worker(someobj *o) :
		o_(o)
	{ }

	virtual void *execute()
	{
		started.signal();
		mayrun.wait();
// DEBUG to

// ... in the worker thread ...
// the thread keeps the someobj in the member o_
	// ... call a method on the other object ...
	bool result = o_->callMethodOnOther();
	// ... destroy our object ...
	delete o_;
// END
// DEBUG from
	o_ = 0;
	return 0;
	}

protected:
	someobj *o_;
};

std::list <worker *> workers;

void makeWorkerThread(someobj *o)
{
	workers.push_back(new worker(o));
}

int main()
{
	const bool symmetric = true;

	createWorkers();
	std::list<worker *>::iterator it;
	if (!symmetric)
		mayrun.signal();
	for (it = workers.begin(); it != workers.end(); ++it) {
		(*it)->start();
		if (!symmetric) {
			started.wait(1);
			usleep(1);
		}
	}
	if (symmetric)
		started.wait(2);
	mayrun.signal();
	for (it = workers.begin(); it != workers.end(); ++it) {
		(*it)->join();
		delete (*it);
	}
	return 0;
}

/* Sample output more likely with symmetric = true
callMethodOnOther on 0x21260d0 other grab succeeded
someMethod on 0x2126010
callMethodOnOther on 0x2126010 other grab succeeded
someMethod on 0x21260d0
*/
/* Sample output more likely with symmetric = false
callMethodOnOther on 0x24ec010 other grab succeeded
someMethod on 0x24ec0d0
callMethodOnOther on 0x24ec0d0 other grab failed
*/
